package com.own.demo.controller;

import com.own.demo.entity.LeftRightDeadLock;
import com.own.demo.entity.User;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.http.MediaType;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @Author zyf
 * @Date 2025-05-29 11:48
 * Description:
 * @Version 1.0
 */

@RestController
@RequestMapping("/api")
public class TestController {


    @GetMapping(value = "/test",
            produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> test() throws FileNotFoundException {

        return WebClient.create().get().uri("https://repo.huaweicloud.com/java/jdk/8u151-b12/")
//                获取响应体的方法
                .retrieve()
//                将响应内容按块读取为字符串流
                .bodyToFlux(String.class)
//                每收到一块数据就打印出来
                .doOnNext(System.out::println)
//                控制每秒推送一次数据给客户端，用于模拟 SSE 流控
                .delayElements(Duration.ofMillis(1000L))
//                数据流结束后执行的操作
                .doFinally(data -> {
                    System.out.println("数据接收完毕，可以在这里执行后续操作");
                });

    }

    @GetMapping(value = "/test2/{num}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> test2(@PathVariable int num) {
        Flux<String> result = Flux
                .fromStream(IntStream.range(1, num).mapToObj(i -> {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                    }
                    IntStream.range(0, 100).mapToObj(String::valueOf).forEach(User::newInstance);
                    return "flux data--" + i;
                }));
        return result;
    }

    @GetMapping(value = "/test3/{num}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> test3(@PathVariable int num) {
        Flux<String> result = Flux
                .fromStream(IntStream.range(1, num).mapToObj(i -> {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                    }
                    return "flux data--" + i;
                }));
        return result;
    }

    @GetMapping(value = "/test4/{num}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Object> test4(@PathVariable int num) {

        Flux<Object> just = Flux.just(IntStream.range(0, num).mapToObj(String::valueOf).toArray());
        just.subscribe(System.out::println);

        just.publish();


        Flux.range(0, 10)
                .map(it -> {
                    System.out.println("当前线程名输出1：" + Thread.currentThread().getName());
                    return it;
                })
//                subscribeOn的作用是在这个开始执行的时候，指定使用的线程调度器
                .publishOn(Schedulers.newParallel("NEW"))
                .map(it -> {
                    System.out.println("当前线程名输出2：" + Thread.currentThread().getName());
                    return it;
                })
                .subscribe();

        return just;
    }

    @GetMapping(value = "/test5/{num}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<Integer> test5(@PathVariable int num) {
        Flux<Integer> range = Flux.range(0, 3);
        range.map(it -> {
                    System.out.println("当前线程名输出1：" + Thread.currentThread().getName());
                    return it;
                })
                .map(it -> {
                    System.out.println("当前线程名输出2：" + Thread.currentThread().getName());
                    return it;
                })
//                subscribeOn的作用是在这个开始执行的时候，指定使用的线程调度器
                .subscribeOn(Schedulers.newParallel("NEW"))
//                虽然我把subscribeOn的操作放在最后，但是在执行的时候，会导致整个流从最开始就在NEW的线程上执行
                .subscribe();
        return range;
    }


    @GetMapping(value = "/test6")
    public Flux<Integer> test6() {
        LeftRightDeadLock lrDeadLock = new LeftRightDeadLock();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                // 为了更好的演示死锁，将两个方法的调用放置到同一个线程中执行
                lrDeadLock.leftToRight();
                lrDeadLock.rightToLeft();
            }, "ThreadA-" + i).start();
        }
        return Flux.range(0, 3);
    }

    //    方法区内存溢出
    @GetMapping(value = "/test7")
    public Flux<Integer> test7() {
        int i = 0;
        try {

            while (true) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMObject.class);
                enhancer.setUseCache(false);
                // 借助CGLib直接操作字节码，生成大量的动态类
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                        return proxy.invokeSuper(obj, args);
                    }
                });

                enhancer.create();
                i++;
            }

        } finally {
            System.out.println("运行次数：" + i);
        }
    }

    static class OOMObject {
    }

    //    直接内存溢出
    @GetMapping(value = "/test8")
    public void test8() {
        // 直接分配128M的直接内存(100M)
        ByteBuffer bb = ByteBuffer.allocateDirect(128 * 1024 * 1204);
    }

    //  常量池溢出
    @GetMapping(value = "/test9")
    public void test9() {
        List<String> list = new ArrayList<>();
        int i = 1;
        try {
            while (true) {
                list.add(UUID.randomUUID().toString().intern());
                i++;
            }
        } finally {
            System.out.println("运行次数：" + i);
        }
    }

    //    对象没有回收
    @GetMapping(value = "/test10")
    public void test10() {
        List<Object> list = new LinkedList<>(); //在方法执行的过程中，它是GCRoots
        int i = 0;

        while (true) {
            i++;
            if (i % 10000 == 0)
                System.out.println("i=" + i);
            list.add(new Object());
        }

    }

}
